using System;
using System.Linq;
using System.Diagnostics.Contracts;

namespace ReactiveCode.Observables
{
    public class Event<TSource>: IDisposable
    {
        IObservable<TSource> _source;
        IDisposable _subscription;
        object _eventSender;

        [ContractInvariantMethod]
        void ObjectInvariant()
        {
            Contract.Invariant((_changed == null) == (_subscription == null));
        }

        public Event(IObservable<TSource> source, object eventSender)
        {
            Contract.Requires<ArgumentNullException>(source != null, "source");
            Contract.Requires<ArgumentNullException>(eventSender != null, "eventSender");
            _source = source;
            _eventSender = eventSender;
        }

        event EventHandler _changed;
        public event EventHandler Changed
        {
            add
            {
                if (value == null)
                    return;
                _changed += value;
                if (_subscription == null)
                {
                    _subscription = _source.Subscribe(
                        onNext: _ => this._changed(_eventSender, EventArgs.Empty),
                        onCompleted: Unsubscribe);
                }
            }
            remove
            {
                _changed -= value;
                if (_changed == null)
                    Unsubscribe();
            }
        }

        void Unsubscribe() 
        {
            if (_subscription != null)
            {
                _subscription.Dispose();
                _subscription = null;
            }
        }
        public void Dispose()
        {
            _changed = null;
            Unsubscribe();
        }
    }
}